package fr.efrei.tradesys.hibernate.daoImpl;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;

import fr.efrei.tradesys.hibernate.HibernateUtil;
import fr.efrei.tradesys.hibernate.beans.Currency;
import fr.efrei.tradesys.hibernate.beans.Rate;
import fr.efrei.tradesys.hibernate.dao.RateDao;

@SuppressWarnings("deprecation")
public class RateDaoImpl implements RateDao
{

	private static RateDaoImpl	instance	= new RateDaoImpl();

	public static RateDaoImpl getInstance()
	{
		return instance;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Rate> getAllRate()
	{
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		Criteria criteria = session.createCriteria(Rate.class);
		List<Rate> list = (List<Rate>) criteria.list();
		return list;
	}

	@SuppressWarnings("unchecked")
	public List<Rate> getLastRates()
	{
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();

		DetachedCriteria maxIdQuery = DetachedCriteria.forClass(Rate.class,
				"reqMaxId");
		maxIdQuery.setProjection(Projections.max("idRate"));
		maxIdQuery.add(Expression.eqProperty("reqMaxId.currency1.code",
				"req.currency1.code"));
		maxIdQuery.add(Expression.eqProperty("reqMaxId.currency2.code",
				"req.currency2.code"));

		DetachedCriteria maxDateQuery = DetachedCriteria.forClass(Rate.class,
				"reqMaxDate");
		maxDateQuery.setProjection(Projections.max("rateDate"));
		maxDateQuery.add(Expression.eqProperty("reqMaxDate.currency1.code",
				"reqMaxId.currency1.code"));
		maxDateQuery.add(Expression.eqProperty("reqMaxDate.currency2.code",
				"reqMaxId.currency2.code"));

		maxIdQuery.add(Subqueries.propertyEq("rateDate", maxDateQuery));
		Criteria criteria = session.createCriteria(Rate.class, "req");
		criteria.add(Subqueries.propertyEq("idRate", maxIdQuery));

		List<Rate> list = (List<Rate>) criteria.list();
		return list;
	}

	@SuppressWarnings("unchecked")
	public List<Rate> getRatesToCurrency(Currency c)
	{
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();

		DetachedCriteria maxIdQuery = DetachedCriteria.forClass(Rate.class,
				"reqMaxId");
		maxIdQuery.setProjection(Projections.max("idRate"));
		maxIdQuery.add(Expression.eqProperty("reqMaxId.currency1.code",
				"req.currency1.code"));
		maxIdQuery.add(Expression.eqProperty("reqMaxId.currency2.code",
				"req.currency2.code"));

		DetachedCriteria maxDateQuery = DetachedCriteria.forClass(Rate.class,
				"reqMaxDate");
		maxDateQuery.setProjection(Projections.max("rateDate"));
		maxDateQuery.add(Expression.eqProperty("reqMaxDate.currency1.code",
				"reqMaxId.currency1.code"));
		maxDateQuery.add(Expression.eqProperty("reqMaxDate.currency2.code",
				"reqMaxId.currency2.code"));

		maxIdQuery.add(Subqueries.propertyEq("rateDate", maxDateQuery));
		Criteria criteria = session.createCriteria(Rate.class, "req").add(
				Restrictions.eq("currency2.code", c.getCode()));
		criteria.add(Subqueries.propertyEq("idRate", maxIdQuery));

		List<Rate> list = (List<Rate>) criteria.list();
		return list;
	}

	@SuppressWarnings("unchecked")
	public List<Rate> getRatesFromCurrency(Currency c)
	{
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();

		DetachedCriteria maxIdQuery = DetachedCriteria.forClass(Rate.class,
				"reqMaxId");
		maxIdQuery.setProjection(Projections.max("idRate"));
		maxIdQuery.add(Expression.eqProperty("reqMaxId.currency1.code",
				"req.currency1.code"));
		maxIdQuery.add(Expression.eqProperty("reqMaxId.currency2.code",
				"req.currency2.code"));

		DetachedCriteria maxDateQuery = DetachedCriteria.forClass(Rate.class,
				"reqMaxDate");
		maxDateQuery.setProjection(Projections.max("rateDate"));
		maxDateQuery.add(Expression.eqProperty("reqMaxDate.currency1.code",
				"reqMaxId.currency1.code"));
		maxDateQuery.add(Expression.eqProperty("reqMaxDate.currency2.code",
				"reqMaxId.currency2.code"));

		maxIdQuery.add(Subqueries.propertyEq("rateDate", maxDateQuery));
		Criteria criteria = session.createCriteria(Rate.class, "req").add(
				Restrictions.eq("currency1.code", c.getCode()));
		criteria.add(Subqueries.propertyEq("idRate", maxIdQuery));

		List<Rate> list = (List<Rate>) criteria.list();
		return list;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Rate getRate(Currency c1, Currency c2)
	{
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();

		DetachedCriteria maxDateQuery = DetachedCriteria.forClass(Rate.class,
				"reqMaxDate");
		maxDateQuery.setProjection(Projections.max("rateDate"));
		maxDateQuery.add(Expression.eqProperty("reqMaxDate.currency1.code",
				"req.currency1.code"));
		maxDateQuery.add(Expression.eqProperty("reqMaxDate.currency2.code",
				"req.currency2.code"));

		Criteria criteria = session.createCriteria(Rate.class, "req")
				.add(Restrictions.eq("currency1.code", c1.getCode()))
				.add(Restrictions.eq("currency2.code", c2.getCode()));
		criteria.add(Subqueries.propertyEq("rateDate", maxDateQuery));

		List<Rate> list = (List<Rate>) criteria.list();
		if (list.size() > 0)
			return list.get(0);
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Rate> getRates(Currency c1, Currency c2)
	{
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		Criteria criteria = session.createCriteria(Rate.class)
				.add(Restrictions.eq("currency1.code", c1.getCode()))
				.add(Restrictions.eq("currency2.code", c2.getCode()))
				.addOrder(Order.desc("rateDate")).setMaxResults(30);
		List<Rate> list = (List<Rate>) criteria.list();
		return list;
	}

	@Override
	public void addRate(Rate r)
	{
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.saveOrUpdate(r);
	}

	@Override
	public void updateRate(Rate r)
	{
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.saveOrUpdate(r);
	}

	@Override
	public void removeRate(Rate r)
	{
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.delete(r);
	}

}
